package com.zhang.gulimall.order.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.rabbitmq.client.Channel;
import com.zhang.gulimall.common.exception.NoStockException;
import com.zhang.gulimall.common.to.MemberTo;
import com.zhang.gulimall.common.to.mq.StockLockedTo;
import com.zhang.gulimall.common.utils.R;
import com.zhang.gulimall.order.entity.OrderItemEntity;
import com.zhang.gulimall.order.enume.OrderStatusEnum;
import com.zhang.gulimall.order.feign.CartFeign;
import com.zhang.gulimall.order.feign.MemberFeign;
import com.zhang.gulimall.order.feign.ProductFeign;
import com.zhang.gulimall.order.feign.WareFeign;
import com.zhang.gulimall.order.service.OrderItemService;
import com.zhang.gulimall.order.vo.*;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zhang.gulimall.common.utils.PageUtils;
import com.zhang.gulimall.common.utils.Query;

import com.zhang.gulimall.order.dao.OrderDao;
import com.zhang.gulimall.order.entity.OrderEntity;
import com.zhang.gulimall.order.service.OrderService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;


@Service("orderService")
public class OrderServiceImpl extends ServiceImpl<OrderDao, OrderEntity> implements OrderService {
    private String member_id;

    @Autowired
    MemberFeign memberFeign;
    @Autowired
    CartFeign cartFeign;
    @Autowired
    ProductFeign productFeign;
    @Autowired
    WareFeign wareFeign;

    @Autowired
    OrderService orderService;
    @Autowired
    OrderItemService orderItemService;

    @Autowired
    RedisTemplate<String, String> redisTemplate;

    @Autowired
    ThreadPoolExecutor executor;
    @Autowired
    RabbitTemplate rabbitTemplate;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<OrderEntity> page = this.page(
                new Query<OrderEntity>().getPage(params),
                new QueryWrapper<>()
        );

        return new PageUtils(page);
    }

    @Override
    public OrderConfirmVo confirmOrder(String memberId, MemberTo member) {
        member_id = memberId;
        OrderConfirmVo orderConfirmVo = new OrderConfirmVo();
        // 获取用户地址
        CompletableFuture<Void> addressFuture = CompletableFuture.runAsync(() -> {
            R r = memberFeign.listByMemberId(memberId);
            List<MemberAddressVo> memberReceiveAddress = JSONArray.parseArray(JSON.toJSONString(r.get("memberReceiveAddress")), MemberAddressVo.class);
            orderConfirmVo.setAddress(memberReceiveAddress);
        }, executor);
        // 获取购物车信息
        CompletableFuture<Void> cartItemsFuture = CompletableFuture.runAsync(() -> {
            R cartItems = cartFeign.getUserCartItems();
            List<OrderItemVo> orderItems = JSONArray.parseArray(JSON.toJSONString(cartItems.get("cartItems")), OrderItemVo.class);
            orderConfirmVo.setItems(orderItems);
        }, executor);
        // 获取用户积分
        orderConfirmVo.setIntegration(member.getIntegration() == null ? 0 : member.getIntegration());
        try {
            cartItemsFuture.get();
            // 总价格和总数量
            int count = 0;
            BigDecimal sum = new BigDecimal(0);
            for (OrderItemVo item : orderConfirmVo.getItems()) {
                sum = sum.add(item.getTotalPrice());
                count += item.getCount();
            }
            orderConfirmVo.setTotal(sum);
            orderConfirmVo.setTotalCount(count);
            orderConfirmVo.setPayPrice(sum.subtract(new BigDecimal(orderConfirmVo.getIntegration())));

            addressFuture.get();
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 向redis中放入防重令牌
        String s = UUID.randomUUID().toString().replace("-", "");
        orderConfirmVo.setOrderToken(s);
        redisTemplate.opsForValue().set("order:token:" + memberId, s, 30, TimeUnit.MINUTES);

        return orderConfirmVo;
    }

    @Transactional
    @Override
    public SubmitResponseVo submitOrder(OrderSubmitVo orderSubmitVo) {
        SubmitResponseVo submitResponseVo = new SubmitResponseVo();
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
        Long execute = redisTemplate.execute(new DefaultRedisScript<>(script, Long.class), Arrays.asList("order:token:" + member_id), orderSubmitVo.getToken());
        if (execute != null && execute == 1L) {
            // redis 删除成功
            System.out.println("令牌删除成功");
            OrderCreateVo orderCreateVo = create(orderSubmitVo);
            // 订单保存
            Integer code = saveOrder(orderCreateVo);
            if (code != 0) {
                System.out.println("库存锁定失败");
                // 订单创建异常,发送库存回滚消息
                rabbitTemplate.convertAndSend("order-event-exchange", "order.create.order", orderCreateVo);
                throw new NoStockException("");
            }
            // code0成功,1失败
            submitResponseVo.setCode(code);
                rabbitTemplate.convertAndSend("order-event-exchange", "order.create.order", orderCreateVo.getOrderItems().get(0).getOrderSn());
            System.out.println("订单保存成功");
        } else {
            System.out.println("令牌删除失败");
            // redis删除失败
            submitResponseVo.setCode(1);
        }
        return submitResponseVo;
    }

    public Integer saveOrder(OrderCreateVo orderCreateVo) {
        // 1.保存订单到数据库
        orderService.save(orderCreateVo.getOrder());
        // 2.保存订单项到数据库
        orderItemService.saveBatch(orderCreateVo.getOrderItems());
        // 3.锁定库存
        R r = wareFeign.lockOrder(orderCreateVo.getOrderItems());

        return r.getCode();
    }

    public OrderCreateVo create(OrderSubmitVo orderSubmitVo) {
        OrderCreateVo orderCreateVo = new OrderCreateVo();
        String orderSn = IdWorker.getTimeId();
        // 1.生成订单实体
        orderCreateVo.setOrder(buildOrderEntity(orderSubmitVo, orderSn));
        // 2.生成订单项
        orderCreateVo.setOrderItems(buildOrderItems(orderSn));
        return orderCreateVo;
    }

    // 生成订单实体
    private OrderEntity buildOrderEntity(OrderSubmitVo orderSubmitVo, String orderSn) {
        OrderEntity order = new OrderEntity();
        order.setMemberId(member_id);
        // 1.订单号
        order.setOrderSn(orderSn);
        // 2.地址
        R r = memberFeign.getByMemberId(orderSubmitVo.getAddrId());
        MemberAddressVo memberReceiveAddress = JSON.parseObject(JSON.toJSONString(r.get("memberReceiveAddress")), MemberAddressVo.class);
        //todo 可以试试用MapStruct进行对象拷贝
        order.setReceiverName(memberReceiveAddress.getName());
        order.setReceiverPhone(memberReceiveAddress.getPhone());
        order.setReceiverPostCode(memberReceiveAddress.getPostCode());
        order.setReceiverProvince(memberReceiveAddress.getProvince());
        order.setReceiverCity(memberReceiveAddress.getCity());
        order.setReceiverRegion(memberReceiveAddress.getRegion());
        order.setReceiverDetailAddress(memberReceiveAddress.getDetailAddress());
        order.setStatus(OrderStatusEnum.CREATE_NEW.getCode());
        return order;
    }

    // 生成订单项
    private List<OrderItemEntity> buildOrderItems(String orderSn) {
        R cartItems = cartFeign.getUserCartItems();
        List<OrderItemVo> orderItems = JSONArray.parseArray(JSON.toJSONString(cartItems.get("cartItems")), OrderItemVo.class);
        return orderItems.stream().map(item -> {
            OrderItemEntity orderItemEntity = new OrderItemEntity();
            // 1.订单信息
            orderItemEntity.setOrderSn(orderSn);
            // 2.spu信息
            R spu = productFeign.getSpuBySkuId(item.getSkuId());
            SpuInfoVo data = JSON.parseObject(JSON.toJSONString(spu.get("data")), SpuInfoVo.class);
            orderItemEntity.setSpuId(data.getId());
            orderItemEntity.setSpuName(data.getSpuName());
            orderItemEntity.setSpuBrand(data.getBrandId());
            orderItemEntity.setSpuPic(data.getSpuDescription());
            orderItemEntity.setCategoryId(data.getCatalogId());
            // 3.sku信息
            orderItemEntity.setSkuId(item.getSkuId());
            orderItemEntity.setSkuName(item.getSkuTitle());
            orderItemEntity.setSkuPic(item.getSkuDefaultImg());
            orderItemEntity.setSkuPrice(item.getPrice());
            orderItemEntity.setSkuQuantity(item.getCount());
            orderItemEntity.setSkuAttrsVals(StringUtils.collectionToDelimitedString(item.getSkuAttr(), ";"));
            return orderItemEntity;
        }).collect(Collectors.toList());
    }

    @Override
    public OrderEntity getOrderStatus(String id) {
        return this.getOne(new LambdaQueryWrapper<OrderEntity>().eq(OrderEntity::getOrderSn, id));
    }
}